/** 
 * This file is part of osami-fin-demo project( http://code.google.com/p/osami-fin-demo/ )
 * @license Apache License 2.0
 */
package org.osami.appevent;

import java.util.Hashtable;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;

/** 'typedef' for registering event listener properties */
class EventTopic extends Hashtable<String, String[]> {
	private static final long serialVersionUID = 0x1L;
}

public class Activator implements BundleActivator, EventHandler {

	public static final String LOG_CATEGORY = "AndroidEventOSGiBundle";

	private BundleContext bundleContext;	
	private Context androidContext;
	
	private ServiceReference serviceRef;
	private EventAdmin eventAdmin;

	ServiceRegistration serviceRegistration;
	PhoneStateReceiver phoneState;
	IncomingSMSReceiver smsReceiver;
	ApplicationEventReceiver appReceiver;
	OSGi2IntentReceiver osgi2IntentReceiver;
	HidManagerBridgeReceiver hidmanagerIntentReceiver;
	
	EventDispatcher eventDispatcher;
	
	// OutgoingCallReceiver outgoingCall;
	
	Logger log = new Logger(this.getClass().getName());

	protected EventTopic getHandlerServiceProperties(String... topics) {
		EventTopic result = new EventTopic();
		result.put(EventConstants.EVENT_TOPIC, topics);
		return result;
	}

	protected EventTopic makePropertiesWithEventTopics(String... topics) {
		EventTopic result = new EventTopic();
		result.put(EventConstants.EVENT_TOPIC, topics);
		return result;
	}

	protected boolean initEventAdmin() {

		ServiceReference eventAdminRef = this.bundleContext
				.getServiceReference(EventAdmin.class.getName());
		if (eventAdminRef == null) {
			log.e("eventAdminRef is null");
			return false;
		}

		this.eventAdmin = (EventAdmin) this.bundleContext.getService(eventAdminRef);
		if (eventAdmin == null) {
			log.e("eventAdmin is null");
			return false;
		}

		// TODO: Create listener for events from the box and android push
		// notifications
		EventTopic eventTopics = makePropertiesWithEventTopics(
				EventDispatcher.MESSAGE_TYPE_CALL_INCOMING,
				EventDispatcher.MESSAGE_TYPE_CALL_OUTGOING,
				EventDispatcher.MESSAGE_TYPE_SMS);

		serviceRegistration = this.bundleContext.registerService(EventHandler.class
				.getName(), this, eventTopics);

		if (serviceRegistration == null) {
			log.e("registerService failed");
			return false;
		}

		return true;
	}

	/** Register phone event broadcast receivers */
	public void start(BundleContext aBundleContext) throws Exception {

		log.d("Starting bundle");
		bundleContext = aBundleContext;

		if (this.initEventAdmin() == false) {
			log.e("Failed to get event admin");
			return;
		}

		eventDispatcher = new EventDispatcher(eventAdmin);

		serviceRef = aBundleContext
				.getServiceReference(Context.class.getName());

		if (serviceRef != null) {
			androidContext = (Context) aBundleContext.getService(serviceRef);

			phoneState = new PhoneStateReceiver(eventDispatcher);
			IntentFilter infilter = new IntentFilter(
					"android.intent.action.PHONE_STATE");
			androidContext.registerReceiver(phoneState, infilter);

			// outgoingCall = new OutgoingCallReceiver(eventDispatcher);
			IntentFilter outfilter = new IntentFilter(
					"android.intent.action.NEW_OUTGOING_CALL");
			androidContext.registerReceiver(phoneState, outfilter);

			smsReceiver = new IncomingSMSReceiver(eventDispatcher);
			IntentFilter smsfilter = new IntentFilter(
					"android.provider.Telephony.SMS_RECEIVED");
			androidContext.registerReceiver(smsReceiver, smsfilter);

			log.d("Call intents registered", phoneState.toString(),
					// outgoingCall.toString(),
					smsReceiver.toString());
			
			appReceiver = new ApplicationEventReceiver(eventDispatcher);
			IntentFilter appfilter = new IntentFilter(
				"org.osami.OSGI_EVENT");
			androidContext.registerReceiver(appReceiver, appfilter);
			
			osgi2IntentReceiver = new OSGi2IntentReceiver(eventDispatcher, androidContext, bundleContext);
			IntentFilter osgiFilter = new IntentFilter(
				"org.osami.OSGI_2_INTENT");
			androidContext.registerReceiver(osgi2IntentReceiver, osgiFilter);
			
			hidmanagerIntentReceiver = new HidManagerBridgeReceiver(eventDispatcher, androidContext);
			IntentFilter hidFilter = new IntentFilter(HidManagerBridgeReceiver.INTENT_ACTION_QUERY);
			androidContext.registerReceiver(hidmanagerIntentReceiver, hidFilter);
			
			log.d("App intents registered");
			
			
		} else {
			log.e("Failed to get service reference");
		}
	}

	protected void unregisterReceiver(BroadcastReceiver aReceiver) {
		// This is called on stop so be extra careful
		if (androidContext == null) {
			return;
		}
		if (aReceiver == null) {
			return;
		}

		androidContext.unregisterReceiver(aReceiver);

	}

	public void stop(BundleContext bc) throws Exception {
		log.d("Stopping bundle");

		if (serviceRegistration != null) {
			serviceRegistration.unregister();
		}
		
		eventDispatcher.unregister();

		unregisterReceiver(phoneState);
		// unregisterReceiver(outgoingCall);
		unregisterReceiver(smsReceiver);
		log.d("Call intents unregistered");
		
		unregisterReceiver(hidmanagerIntentReceiver);
		unregisterReceiver(osgi2IntentReceiver);
		unregisterReceiver(appReceiver);
		
		log.d("App intents unregistered");
	}

	public void handleEvent(Event event) {
		log.w("TODO: Remove, this is just for testing");
		log.d("Got event from EventAdmin", event.toString());
		
		// if(event.getTopic() == EventDispatcher.MESSAGE_TYPE_CALL_INCOMING){
		String[] properties = event.getPropertyNames();
		for (String name : properties) {
			log.d(name, "=", event.getProperty(name));
		}
		// }
	}
}
